// Copyright(c) 2008 Tri Tech Information Systems Inc. 
// Distributed under the Boost Software License, Version 1.0.
//     (See accompanying file ../../LICENSE_1_0.txt or copy at
//           http://www.boost.org/LICENSE_1_0.txt)
//     
#ifndef INCLUDE_PYTHON_UTIL_H
#define INCLUDE_PYTHON_UTIL_H

#include <iostream>
#include <boost/python.hpp>
#include <vector>
#include <map>
#include "pair.h"
/*
    register_raw_ptr_to_python

    Causes any raw pointers being converted into python to be converted
    into a reference to that object. Use only for objects which will 
    not be destroyed while python is operating.

    Pass the actual class type, not a pointer to it.
          
*/   


/*
   Register wrappers to be called when python imports a module

*/

struct RegisterWrapperBase
{
    RegisterWrapperBase():
        m_wrapped(false)
    {
    }
    virtual bool Wrap(bool forced = false) = 0;

    static std::vector<RegisterWrapperBase*> & Wrappers(const std::string &key)
    {
        static std::map<
            std::string,
            std::vector<RegisterWrapperBase*>
               > wrappers;
        return wrappers[key];
    }

    bool m_wrapped;
};

template<typename WrapperType>
struct RegisterWrapper : public RegisterWrapperBase
{
    RegisterWrapper(const std::string& key)
    {
        Wrappers(key).push_back(this);
    }  

    virtual bool Wrap(bool forced)
    {
        if( m_wrapped )
            return false;

        if( forced ||  WrapperType::__Ready() )
        {
            WrapperType::__WrapClass();
            m_wrapped = true;
            return true;
        }
        else
        {
            return false;
        }
    }

};

inline void ExecuteWrappers(const std::string& key)
{
    std::vector<RegisterWrapperBase*> & wrappers = RegisterWrapperBase::Wrappers(key);

    bool did_something = true;
    while(did_something)
    {
        did_something = false;
        for(std::vector<RegisterWrapperBase*>::iterator iter = wrappers.begin();
                iter != wrappers.end(); iter++)
        {
            if( (*iter)->Wrap() )
            {
                did_something = true;
            }
        }
    }
    bool errored = false;

    for(std::vector<RegisterWrapperBase*>::iterator iter = wrappers.begin();
            iter != wrappers.end(); iter++)
    {
        try
        {
              (*iter)->Wrap(true);
        }
        catch(boost::python::error_already_set&)
        {
            PyErr_Print();
            errored = true;
        }
    }

    if(errored)
    {
        throw std::runtime_error("Some wrappers failed");
    }

}

template<typename ClassType>
bool is_wrapped()
{
    using namespace boost::python::converter;
    using namespace boost::python;
    registration const * p = registry::query( type_id<ClassType>() );
    return p && p->m_class_object;
}

#endif
